package me.yuzho.study.concurrency;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static net.mindview.util.Print.*;


class Blocker {
    synchronized void waitingCall() {
        try {
            
            while(!Thread.interrupted()) {
                wait();
                System.out.print(Thread.currentThread() + "");
            }
        } catch(InterruptedException e) {
            
        }
    }
    
    synchronized void prod() { notify();}
    synchronized void prodAll() {notifyAll();}
}

class Task implements Runnable {
    static Blocker blocker = new Blocker();
    public void run() { blocker.waitingCall();}
}

class Task2 implements Runnable {
    static Blocker blocker = new Blocker();
    public void run() { blocker.waitingCall();}
}

/** In the following example, the code associated with Task2 shows that only the tasks
 * that are waiting on a particular lock are awaken when notifyAll() is  called/or that lock 
 * @author yzhou-citrix
 *
 */
public class NotifyVsNotifyAll {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newCachedThreadPool();
        for(int i=0; i<5; i++) {
            exec.execute(new Task());
        }
        
        exec.execute(new Task2());
        
        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            boolean prod = true;
            @Override
            public void run() {
                if(prod) {
                   printnb("\nnotify() ");
                   Task.blocker.prod();
                   prod = false;
                } else {
                   printnb("\nnotifyAll() ");
                   Task.blocker.prodAll();
                   prod = true; 
                }
                
            }
        }, 400, 400); // Run every .4 second
        
        TimeUnit.SECONDS.sleep(5);
        
        timer.cancel();
        print("\nTimer canceled");
        
        TimeUnit.MILLISECONDS.sleep(500);
        print("Task2.blocker.prodAll() ");
        Task2.blocker.prodAll();
        
        TimeUnit.MILLISECONDS.sleep(500);
        print("\nShutting down");
        exec.shutdownNow(); 
    }
}
